package com.shanzhu.beadhouse.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.shanzhu.beadhouse.common.constant.ChargeEnum;
import com.shanzhu.beadhouse.common.constant.ExceptionEnum;
import com.shanzhu.beadhouse.common.constant.YesNoEnum;
import com.shanzhu.beadhouse.common.util.AssertUtil;
import com.shanzhu.beadhouse.common.util.PageUtil;
import com.shanzhu.beadhouse.entity.base.DropDown;
import com.shanzhu.beadhouse.entity.base.PageResult;
import com.shanzhu.beadhouse.entity.base.Result;
import com.shanzhu.beadhouse.dao.mapper.ServiceItemMapper;
import com.shanzhu.beadhouse.dao.mapper.ServiceTypeMapper;
import com.shanzhu.beadhouse.entity.po.ServiceItem;
import com.shanzhu.beadhouse.entity.po.ServiceType;
import com.shanzhu.beadhouse.entity.query.*;
import com.shanzhu.beadhouse.entity.vo.OperateServiceTypeVo;
import com.shanzhu.beadhouse.entity.vo.OperateServiceVo;
import com.shanzhu.beadhouse.entity.vo.PageServiceByKeyVo;
import com.shanzhu.beadhouse.entity.vo.PageServiceLogVo;
import com.shanzhu.beadhouse.service.ServiceProjectService;
import com.shanzhu.beadhouse.service.common.ServiceItemFunc;
import com.shanzhu.beadhouse.service.common.ServiceTypeFunc;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import com.shanzhu.beadhouse.common.constant.RedisConstant;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class ServiceProjectServiceImpl implements ServiceProjectService {
    @Resource
    private ServiceTypeMapper serviceTypeMapper;
    @Resource
    private ServiceTypeFunc serviceTypeFunc;
    @Resource
    private ServiceItemMapper serviceItemMapper;
    @Resource
    private ServiceItemFunc serviceItemFunc;
    @Resource
    private PageUtil pageUtil;
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public Result listServiceType(String serviceTypeName) {
        String types = stringRedisTemplate.opsForValue().get(RedisConstant.SERVICE_TYPE_KEY);
        if (types==null||types.isEmpty()){//如果redis没有值
            String uuid = java.util.UUID.randomUUID().toString();//唯一标识
            try {
                // 尝试获取锁
                Boolean locked = stringRedisTemplate.opsForValue()
                        .setIfAbsent(RedisConstant.SERVICE_TYPE_LOCK, uuid, 3, TimeUnit.MINUTES);

                if (Boolean.TRUE.equals(locked)) {
                    try {
                        // 从数据库查询
                        List<DropDown> list = BeanUtil.copyToList(
                                serviceTypeFunc.listNotDelServiceType(serviceTypeName),
                                DropDown.class
                        );

                        // 写入缓存
                        stringRedisTemplate.opsForValue()
                                .set(RedisConstant.SERVICE_TYPE_KEY, JSONUtil.toJsonStr(list));

                        return Result.success(list);
                    } finally {
                        // 使用Lua脚本确保只有锁的持有者才能删除锁
                        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                                "return redis.call('del', KEYS[1]) " +
                                "else " +
                                "return 0 " +
                                "end";

                        stringRedisTemplate.execute(
                                new DefaultRedisScript<>(script, Long.class),
                                Collections.singletonList(RedisConstant.SERVICE_TYPE_LOCK),
                                uuid
                        );
                    }
                } else {
                    Thread.sleep(30);
                    return listServiceType(serviceTypeName);
                }
            } catch (Exception e) {
                // 异常处理
                return Result.error(500, "系统异常");
            }

        }else {
            List<DropDown> list = JSONUtil.toList(types,DropDown.class);
            return Result.success(list);
        }
    }

    @Override
    public Result pageServiceByKey(PageServiceByKeyQuery query) {
        // 根据搜索关键字查询服务项目
        List<ServiceItem> listNotDelServiceItem = serviceItemFunc.listNotDelServiceItemByKey(query.getName(), query.getTypeId(), ChargeEnum.ALL.getMethod());
        // 实体转换
        List<PageServiceByKeyVo> pageServiceByKeyVoList = BeanUtil.copyToList(listNotDelServiceItem, PageServiceByKeyVo.class);
        // 封装返回数据
        PageResult<PageServiceByKeyVo> pageResult = pageUtil.packPageResultData(pageServiceByKeyVoList, query.getPageNum(), query.getPageSize());
        return Result.success(pageResult);
    }

    @Override
    public Result addServiceType(OperateServiceTypeQuery query) {
        // 验证服务类型名称是否重复
        AssertUtil.isNull(serviceTypeFunc.getServiceTypeByName(query.getName()), ExceptionEnum.SERVICE_TYPE_REPEAT);
        // 验证总数是否超出限制
        AssertUtil.notTrue(serviceTypeFunc.checkTypeTotal(), ExceptionEnum.SERVICE_TYPE_OUT);
        // 初始化服务类型
        query.setId(null);
        ServiceType serviceType = BeanUtil.toBean(query, ServiceType.class);
        serviceType.setDelFlag(YesNoEnum.NO.getCode());
        // 新增
        serviceTypeMapper.insert(serviceType);
        upDateTyPeCache();
        return Result.success();
    }

    @Override
    public Result getServiceTypeById(Long serviceTypeId) {
        // 根据编号获取服务项目分类
        ServiceType serviceType = serviceTypeMapper.selectById(serviceTypeId);
        // 判断是否为空
        AssertUtil.notNull(serviceType, ExceptionEnum.DATA_NOT_EXIST);
        return Result.success(BeanUtil.toBean(serviceType, OperateServiceTypeVo.class));
    }

    @Override
    public Result editServiceType(OperateServiceTypeQuery query) {
        // 验证服务类型名称是否重复
        ServiceType serviceTypeByName = serviceTypeFunc.getServiceTypeByName(query.getName());
        boolean checkName = serviceTypeByName != null && !Objects.equals(serviceTypeByName.getId(), query.getId());
        AssertUtil.notTrue(checkName, ExceptionEnum.SERVICE_TYPE_REPEAT);
        // 封装修改
        ServiceType serviceType = BeanUtil.toBean(query, ServiceType.class);
        // 修改
        serviceTypeMapper.updateById(serviceType);
        upDateTyPeCache();
        return Result.success();
    }

    @Override
    public Result deleteServiceType(Long serviceTypeId) {
        // 判断该分类下是否存在子级服务
        AssertUtil.notTrue(serviceItemFunc.checkServiceItem(serviceTypeId), ExceptionEnum.SERVICE_NOT_NULL);
        // 封装修改
        ServiceType serviceType = new ServiceType();
        serviceType.setId(serviceTypeId);
        serviceType.setDelFlag(YesNoEnum.YES.getCode());
        // 修改
        serviceTypeMapper.updateById(serviceType);
        upDateTyPeCache();
        return Result.success();
    }

    @Override
    public Result addService(OperateServiceQuery query) {
        // 判断服务是否存在
        AssertUtil.isNull(serviceItemFunc.getServiceItemByName(query.getName(), query.getTypeId()), ExceptionEnum.SERVICE_REPEAT);
        // 判断服务总数是否超过总数限制
        AssertUtil.notTrue(serviceItemFunc.checkServiceTotal(query.getTypeId()), ExceptionEnum.SERVICE_OUT);
        // 初始化服务
        query.setId(null);
        ServiceItem serviceItem = BeanUtil.toBean(query, ServiceItem.class);
        serviceItem.setDelFlag(YesNoEnum.NO.getCode());
        // 新增
        serviceItemMapper.insert(serviceItem);
        return Result.success();
    }

    @Override
    public Result getServiceById(Long serviceId) {
        // 根据编号获取服务项目
        ServiceItem serviceItem = serviceItemMapper.selectById(serviceId);
        // 判断是否为空
        AssertUtil.notNull(serviceItem, ExceptionEnum.DATA_NOT_EXIST);
        return Result.success(BeanUtil.toBean(serviceItem, OperateServiceVo.class));
    }

    @Override
    public Result editService(OperateServiceQuery query) {
        // 判断服务是否存在
        ServiceItem serviceItemByName = serviceItemFunc.getServiceItemByName(query.getName(), query.getTypeId());
        boolean checkName = serviceItemByName != null && !Objects.equals(serviceItemByName.getId(), query.getId());
        AssertUtil.notTrue(checkName, ExceptionEnum.SERVICE_REPEAT);
        // 封装修改
        ServiceItem serviceItem = BeanUtil.toBean(query, ServiceItem.class);
        // 修改
        serviceItemMapper.updateById(serviceItem);
        return Result.success();
    }

    @Override
    public Result deleteService(Long serviceId) {
        // 封装修改
        ServiceItem serviceItem = new ServiceItem();
        serviceItem.setId(serviceId);
        serviceItem.setDelFlag(YesNoEnum.YES.getCode());
        // 修改
        serviceItemMapper.updateById(serviceItem);
        return Result.success();
    }

    @Override
    public Result pageUnPurchaseByKeys(PagePurchaseByKeysQuery query) {
        List<PageServiceLogVo> pageServiceLogVoList = serviceItemMapper.listUnPurchaseItemLogByKey(query);
        PageResult<PageServiceLogVo> pageResult = pageUtil.packPageResultData(pageServiceLogVoList,query.getPageNum(),query.getPageSize());
        return Result.success(pageResult);
    }

    @Override
    public Result pageServiceToLevel(PageServiceToAddQuery query) {
        // 根据搜索关键字查询服务项目
        List<ServiceItem> listNotDelServiceItem = serviceItemMapper.listServiceToLevel(query);
        // 实体转换
        List<PageServiceByKeyVo> pageServiceByKeyVoList = BeanUtil.copyToList(listNotDelServiceItem, PageServiceByKeyVo.class);
        // 封装返回数据
        PageResult<PageServiceByKeyVo> pageResult = pageUtil.packPageResultData(pageServiceByKeyVoList, query.getPageNum(), query.getPageSize());
        return Result.success(pageResult);
    }


    private void upDateTyPeCache(){
        stringRedisTemplate.delete(RedisConstant.SERVICE_TYPE_KEY);
    }
}
